﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChatClient
{
    public partial class ChatClient : Form
    {
        Socket ClientSocket { set; get; }
        public ChatClient()
        {
            InitializeComponent();
            //Control.CheckForIllegalCrossThreadCalls = false;//设置不捕捉错误线程
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (ClientSocket == null)
            {
                //建立Socket
                ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                try
                {
                    //开始连接
                    ClientSocket.Connect(System.Net.IPAddress.Parse(txtIP.Text), int.Parse(txtPoint.Text));
                    //创建线程接受消息
                    Thread thread = new Thread(new ParameterizedThreadStart(ReceiveServerMsg));
                    thread.IsBackground = true;
                    thread.Start(ClientSocket);

                }
                catch (Exception)
                {
                    MessageBox.Show("连接服务器失败,3秒后为您重新连接...");
                    Thread.Sleep(3000);
                    btnConnect_Click(this, e);

                }
            }
            else
            {
                AppendStringToLog(string.Format("已连接服务端{0}{1},请勿重复连接操作...",
                    txtIP.Text, txtPoint.Text));
            }

        }

        /// <summary>
        /// 向服务端发送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            byte[] data = Encoding.Default.GetBytes(txtMsg.Text);
            if (ClientSocket != null && ClientSocket.Connected)
            {
                ClientSocket.Send(data, 0, data.Length, SocketFlags.None);
            }
            else
            {
                AppendStringToLog("当前没有连上服务器,请连接服务器后再尝试发送消息...");
            }
        }

        int len = 3;
        //接收服务端的消息
        private void ReceiveServerMsg(object socket)
        {
            var clientSocket = socket as Socket;
            if (socket != null)
            {
                AppendStringToLog(string.Format("成功连接服务器:{0}...", clientSocket.RemoteEndPoint.ToString()));
            }
            byte[] data = new Byte[1024 * 1024];
            while (true)
            {
                try
                {
                    len = clientSocket.Receive(data, 0, data.Length, SocketFlags.None);
                    if (data[0] == 0)
                    {
                        this.AppendStringToLog(string.Format("接收到服务器{0}发来的消息:{1}",
                        clientSocket.RemoteEndPoint.ToString(), Encoding.Default.GetString(data, 1, len - 1)));
                    }
                    else if (data[0] == 1)
                    {
                        //震动
                        ScreenShake();
                    }
                    else if (data[0] == 2)
                    {
                        //文件
                        //OpenFileDialog ofd = new OpenFileDialog();
                        //if (ofd.ShowDialog() != DialogResult.OK)
                        //{
                        //    return;
                        //}
                        //using (FileStream file = new FileStream(ofd.FileName,FileMode.CreateNew,FileAccess.Write))
                        //{
                        //    file.Write(data,1,data.Length-1);
                        //}
                        //屏蔽代码会引发如下异常:
                        //在可以调用 OLE 之前，必须将当前线程设置为单线程单元(STA)模式,
                        //请确保您的 Main 函数带有 STAThreadAttribute 标记, 只有将调试程序附加到该进程才会引发此异常。
                        Thread thread = new Thread(new ParameterizedThreadStart(CreateFile));
                        thread.SetApartmentState(ApartmentState.STA);
                        thread.Start(data);
                    }
                    if (len <= 0)
                    {
                        //服务端正常退出
                        this.AppendStringToLog(string.Format("服务器{0}正常退出...",
                            clientSocket.RemoteEndPoint.ToString()));
                        StopConnect();
                    }
                }
                catch (Exception ex)
                {

                    //服务器端非正常退出
                    this.AppendStringToLog(string.Format("服务器{0}非正常退出...", clientSocket.RemoteEndPoint));
                    StopConnect();
                    return;
                }
            }
        }

        private void AppendStringToLog(string str)
        {
            if (txtLog.InvokeRequired)
            {
                txtLog.BeginInvoke(new Action<string>(s =>
                {
                    this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text);
                }), str);
            }
            else
            {
                this.txtLog.Text = string.Format("{0}\r\n{1}", str, txtLog.Text);
            }
        }


        /// <summary>
        /// 断开连接
        /// </summary>
        private void StopConnect()
        {
            try
            {
                if (ClientSocket.Connected)
                {
                    ClientSocket = null;
                    ClientSocket.Shutdown(SocketShutdown.Both);
                    ClientSocket.Close(100);


                }
            }
            catch (Exception)
            {
                Thread.CurrentThread.Abort();
            }
        }

        private void ScreenShake()
        {
            Random random = new Random();
            Point oldPoint = this.Location;
            if (txtLog.InvokeRequired)
            {
                //所有用到跨线程控件都得写到Invok委托中去
                this.txtLog.Invoke(new Action(() =>
                {
                    for (int i = 0; i < 50; i++)
                    {
                        this.Location = new Point(random.Next(oldPoint.X - 10, oldPoint.X + 10),
                            random.Next(oldPoint.Y - 10, oldPoint.Y + 10));
                    }
                    Thread.Sleep(50);
                    this.Location = oldPoint;
                }));
            }
        }

        public void CreateFile(object write)
        {
            byte[] data = write as byte[];
            //文件
            SaveFileDialog ofd = new SaveFileDialog();
            ofd.Filter = "txt|*.txt|应用程序|*.exe";
            if (ofd.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            using (FileStream file = new FileStream(ofd.FileName, FileMode.CreateNew, FileAccess.Write))
            {
                file.Write(data, 1, len - 1);
            }
        }

        //发送报文
        private void btnSend1_Click(object sender, EventArgs e)
        {
            string Flag = txtMsgFlag.Text;
            string Content = txtMsgContent.Text;
            byte[] msgID;
            short realContent;
            if (!(Flag.Length == 6 || Flag.Length == 4))
            {
                MessageBox.Show("报文表示长度必须为(4 OR 6)", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return;
            }
            bool f = short.TryParse(Content, out realContent);
            if (!f)
            {
                MessageBox.Show("报文范围为-32768~32767", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return;
            }
            if (ClientSocket.Connected)
            {
                byte[] Msg = new byte[10];
                byte[] msgLength = BitConverter.GetBytes((short)32767);
                if (strToToHexByte(Flag) != null)
                {
                    msgID = strToToHexByte(Flag);
                }
                else
                {
                    MessageBox.Show("报文标识不规范!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    return;
                }
                byte[] msgSeq = BitConverter.GetBytes((short)32767);
                byte[] flag = BitConverter.GetBytes((short)32767);
                byte[] msgReal = BitConverter.GetBytes(realContent);
                Array.Copy(msgLength, 0, Msg, 0, 2);
                Array.Copy(msgID, 0, Msg, 2, 2);
                Array.Copy(msgSeq, 0, Msg, 4, 2);
                Array.Copy(flag, 0, Msg, 6, 2);
                Array.Copy(msgReal, 0, Msg, 8, 2);
                ClientSocket.Send(Msg, 0, Msg.Length, SocketFlags.None);
            }


        }

    /// <summary>
    /// 字符串转16进制字节数组
    /// </summary>
    /// <param name="hexString"></param>
    /// <returns></returns>
    private static byte[] strToToHexByte(string hexString)
    {
        if (hexString.Substring(0, 2).ToLower() == "0x")
        {
            hexString = hexString.Substring(2);
        }
        byte[] returnBytes = new byte[hexString.Length / 2];
        for (int i = 0; i < returnBytes.Length; i++)
            try
            {
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            catch (Exception ex)
            {
                return null; ;
            }
        return returnBytes;
    }
}
}
